import java.util.Random;
import java.util.HashMap;
import java.util.Set;

public class KantineSimulatie
{
    // kantine
    private Kantine kantine;
    
    // Kantine aanbod
    private KantineAanbod kantineAanbod;
    
    // Random number generator
    private Random random;
    
    // Minimum en Maximum aantal artikelen per soort
    private int minArtikelenPerSoort = 10000;
    private int maxArtikelenPerSoort = 20000;
    
    // minimum en maximum aantal personen per dag
    private int minPersonenPerDag = 50; 
    private int maxPersonenPerDag = 100; 
 
    // minimum en maximum artikelen per persoon 
    private int minArtikelenPerPersoon = 1; 
    private int maxArtikelenPerPersoon = 4;
    
    // betaalwijze distributie
    private static final int PROBABILITY_PINPAS = 50;
    
    // pinpas krediet min/max
    private static final int PINPAS_KREDIET_MIN = 0;
    private static final int PINPAS_KREDIET_MAX = 10;
    
    // saldo min/max
    private static final int PERSOON_SALDO_MIN = 0;
    private static final int PERSOON_SALDO_MAX = 10;
    
    private GUI gui;
    
    /** 
     * Constructor die standaard waarden gebruikt
     */ 
    public KantineSimulatie()
    { 
        kantine = new Kantine(); 
        random = new Random(); 
        
        kantineAanbod = new KantineAanbod();
        kantine.setKantineAanbod(kantineAanbod); 
    } 
    
    public void setGUI(GUI gui)
    {
        this.gui = gui;
    }
    
    public void configureer(int minArtikelenPerSoort, int maxArtikelenPerSoort, int minArtikelenPerPersoon, int maxArtikelenPerPersoon, int minPersonenPerDag, int maxPersonenPerDag)
    {
        this.minArtikelenPerSoort = minArtikelenPerSoort;
        this.maxArtikelenPerSoort = maxArtikelenPerSoort;
        this.minArtikelenPerPersoon = minArtikelenPerPersoon;
        this.maxArtikelenPerPersoon = maxArtikelenPerPersoon;
        this.minPersonenPerDag = minPersonenPerDag;
        this.maxPersonenPerDag = maxPersonenPerDag;
    }
 
    /** 
     * Methode om een array van random getallen liggend tussen min en max  
     * van de gegeven lengte te genereren 
     * @param lengte 
     * @param min 
     * @param max 
     * @return De array met random getallen 
     */ 
    private int[] getRandomArray(int lengte, int min, int max)  
    { 
        int[] temp=new int[lengte]; 
        for(int i = 0; i < lengte; i++) { 
            temp[i] = getRandomValue(min, max); 
        } 
        return temp; 
    } 
 
    /** 
     * Methode om een random getal tussen min(incl) en max(incl) te genereren. 
     * @param min 
     * @param max 
     * @return Een random getal 
     */ 
    private int getRandomValue(int min, int max)  
    { 
        return random.nextInt(max - min + 1) + min; 
    } 
  
    /** 
     * Methode om op basis van een array van indexen voor de array  
     * artikelnamen de bijhorende array van artikelnamen te maken 
     * @param indexen 
     * @return De array met artikelnamen 
     */ 
    private String[] geefArtikelNamen(int[] indexen)
    { 
        String[] artikelen=new String[indexen.length]; 
        for(int i = 0; i < indexen.length; i++)  
        {  
            artikelen[i] = kantineAanbod.getArtikelnaamById(indexen[i]); 
        } 
        return artikelen; 
    } 

    /** 
     * Deze methode simuleert een aantal dagen in het verloop van de kantine 
     * @param dagen 
     */ 
    public void simuleer(int dagen)  
    {
        if(kantineAanbod.getAantalArtikelen() == 0) {
            output("Er kan geen simulatie worden uitgevoerd als er geen artikelen in het kantineaanbod staan.");
            return;
        }
        
        double[] dagOmzetten = new double[dagen];
        int[] dagProductVerkopen = new int[dagen];
        
        // for lus voor dagen 
        for(int i = 0; i < dagen; i++) {
            int personenVandaag = getRandomValue(minPersonenPerDag, maxPersonenPerDag);
            
            // laat de personen maar komen
            for(int j = 0; j < personenVandaag; j++) {
                // declareer persoon (buiten if scope!)
                Persoon persoon;
                
                // Genereer random nummer
                int randomNumber = getRandomValue(0, 99);
                
                // maak persoon, als random nummer < 89, dan student, 89 - 98 docent, 99 kantine medewerker
                if(randomNumber < 89) {
                    persoon = new Student("", "", "", "Student", "" + j, 0, 0, 0, "");
                }
                else if(randomNumber < 99) {
                    persoon = new Docent("", "", "", "Docent", "" + j, 0, 0, 0, "");
                }
                else {
                    persoon = new KantineMedewerker(false, "", "", "Medewerker", "" + j, 0, 0, 0, "");
                }
                
                // Maak dienblad
                Dienblad dienblad = new Dienblad();
                
                // Voeg dienblad toe aan persoon
                persoon.pakDienblad(dienblad);
                
                // Maak betaalwijze
                Betaalwijze betaalwijze;
                
                // Selecteer een random betaalwijze
                if(getRandomValue(0, 99) < PROBABILITY_PINPAS) {
                    Pinpas pinpas = new Pinpas();
                    pinpas.setKredietLimiet(getRandomValue(PINPAS_KREDIET_MIN, PINPAS_KREDIET_MAX));
                    betaalwijze = pinpas;
                }
                else {
                    betaalwijze = new Contant();
                }
                
                double saldo = (double) getRandomValue(PERSOON_SALDO_MIN, PERSOON_SALDO_MAX);
                //output("Saldo van persoon: " + saldo);
                betaalwijze.setSaldo(saldo);
                persoon.setBetaalwijze(betaalwijze);
                
                // bedenk hoeveel artikelen worden gepakt 
                int aantalartikelen = getRandomValue(minArtikelenPerPersoon, maxArtikelenPerPersoon);
                //output("Aantal artikelen: " + aantalartikelen);
                
                // genereer de “artikelnummers”, dit zijn indexen  
                // van de artikelnamen array
                int[] tepakken = getRandomArray(aantalartikelen, 0, kantineAanbod.getAantalArtikelen() - 1); 
    
                // vind de artikelnamen op basis van de indexen hierboven 
                String[] artikelen = geefArtikelNamen(tepakken); 
                 
                // loop de kantine binnen, pak de gewenste artikelen
                kantine.loopPakSluitAan(persoon, artikelen);
                //output(persoon);
            } 
    
            // verwerk rij voor de kassa
            output("");
            boolean rijNietVerwerkt = true;
            while(rijNietVerwerkt) {
                try {
                    kantine.verwerkRijVoorKassa();
                    rijNietVerwerkt = false;
                }
                catch(TeWeinigGeldException e) {
                    output(e.getMessage());
                }
            }
    
            // druk de dagtotalen af en hoeveel personen binnen zijn gekomen 
            output("= Dag totaal ==============================");
            output("Aantal verkochte producten: "+kantine.getKassa().aantalArtikelen());
            output("Geld in kassa: "+kantine.getKassa().hoeveelheidGeldInKassa());
            
            // Voeg dag omzet en verkocht aantal artikelen aan arrays
            dagOmzetten[i] = kantine.getKassa().hoeveelheidGeldInKassa();
            dagProductVerkopen[i] = kantine.getKassa().aantalArtikelen();
            
            // reset de kassa voor de volgende dag 
            kantine.getKassa().resetKassa();
            kantineAanbod.vulAanbod(minArtikelenPerSoort);
            //showVoorraad();
        }
        
        // Druk gemiddeld aantal verkopen per dag, gemidddelde dag omzet, en gemiddelde omzet per dag van week
        output("= Simulatie resultaten ====================");
        output("Gemiddelde dagomzet: " + Administratie.berekenGemiddeldeOmzet(dagOmzetten));
        output("Gemiddeld aantal producten per dag: " + Administratie.berekenGemiddeldAantal(dagProductVerkopen));
        output("");
        double[] omzetVanDag = Administratie.berekenDagOmzet(dagOmzetten);
        String[] dagenVanWeek = new String[] {"Maandag: ", "Dinsdag: ", "Woensdag: ", "Donderdag: ", "Vrijdag: ", "Zaterdag: ", "Zondag: "};
        for(int dag = 0; dag < 7; dag++) {
            output(dagenVanWeek[dag] + omzetVanDag[dag]);
        }
            
    }
    
    public void artikelToevoegen(String artikelnaam, double prijs)
    {
        kantineAanbod.addArtikel(artikelnaam, prijs, getRandomValue(minArtikelenPerSoort, maxArtikelenPerSoort));
    }
    
    public void artikelToevoegen(String artikelnaam, double prijs, int hoeveelheid)
    {
        kantineAanbod.addArtikel(artikelnaam, prijs, hoeveelheid);
    }
    
    public void showVoorraad()
    {
        output("Voorraad:");
        HashMap<String, String> voorraad = kantineAanbod.getVoorraad();
        Set<String> keys = voorraad.keySet();
        for (String key: keys) {
            output(voorraad.get(key) + " " + key);
        }        
    }
    
    public void output(String output)
    {
        if(gui == null) {
            System.out.println(output);
        }
        else {
            gui.print(output + "\n");
        }
    }
}
